package image.dithering;
 
 
 
 public class Dithering
 {
     private static byte plus_truncate_uchar(byte a, int b) {
         if ((a & 0xff) + b < 0)
             return 0;
         else if ((a & 0xff) + b > 255)
             return (byte)255;
         else
             return (byte)(a + b);
     }
 
 
     private static byte findNearestColor(RGBTriple color, RGBTriple[] palette) {
         int minDistanceSquared = 255*255 + 255*255 + 255*255 + 1;
         byte bestIndex = 0;
         for (byte i = 0; i < palette.length; i++) {
             int Rdiff = (color.channels[0] & 0xff) - (palette[i].channels[0] & 0xff);
//             System.out.println(Rdiff);
             int Gdiff = (color.channels[1] & 0xff) - (palette[i].channels[1] & 0xff);
             int Bdiff = (color.channels[2] & 0xff) - (palette[i].channels[2] & 0xff);
             int distanceSquared = Rdiff*Rdiff + Gdiff*Gdiff + Bdiff*Bdiff;
             if (distanceSquared < minDistanceSquared) {
                 minDistanceSquared = distanceSquared;
                 bestIndex = i;
             }
         }
         return bestIndex;
     }
 
 
     public static byte[][] floydSteinbergDither(RGBTriple[][] image, RGBTriple[] palette)
     {
         byte[][] result = new byte[image.length][image[0].length];
 
 
         for (int y = 0; y < image.length; y++) {
 	    for (int x = 0; x < image[y].length; x++) {
             RGBTriple currentPixel = image[y][x];
             byte index = findNearestColor(currentPixel, palette);
 	    result[y][x] = index;
 
             for (int i = 0; i < 3; i++)
 	    {
 	        int error = (currentPixel.channels[i] & 0xff) - (palette[index].channels[i] & 0xff);
 		if (x + 1 < image[0].length) {
 		    image[y+0][x+1].channels[i] =
 		        plus_truncate_uchar(image[y+0][x+1].channels[i], (error*7) >> 4);
 		}
 		if (y + 1 < image.length) {
 		    if (x - 1 > 0) {
 		        image[y+1][x-1].channels[i] =
 		            plus_truncate_uchar(image[y+1][x-1].channels[i], (error*3) >> 4);
 		    }
 		    image[y+1][x+0].channels[i] =
 		        plus_truncate_uchar(image[y+1][x+0].channels[i], (error*5) >> 4);
 		    if (x + 1 < image[0].length) {
 		        image[y+1][x+1].channels[i] =
 		            plus_truncate_uchar(image[y+1][x+1].channels[i], (error*1) >> 4);
 		    }
 		}
 
 	    }
 
             }
 	}
 
         return result;
     }
 
 
     public static int[][] getDithered8Of(int[][][] orig) {
    	 byte[][] byt = new byte[orig[0].length][orig[0][0].length];
    	 RGBTriple[][] img = new RGBTriple[orig[0].length][orig[0][0].length]; 
    	 
		 for (int x=0;x<orig[0].length;x++)
			 for (int y=0;y<orig[0][0].length;y++) {
				img[x][y]=new RGBTriple(orig[0][x][y], orig[1][x][y], orig[2][x][y]); 
			 }
		 
         /*
			 * CONVERSION TABLE
			 *
			 * C=4		M=2		Y=1
			 *
			 * 		C	M	Y
			 * 0					= 0
			 * 1	X				= 4
			 * 2		X			= 2
			 * 3			X		= 1
			 * 4	X	X			= 6
			 * 5		X	X		= 3
			 * 6	X		X		= 5
			 * 7	X	X	X		= 7 negro
			 *
			 *
			 * difungir
			 */
		 
         RGBTriple[] palette = {
                 new RGBTriple(255, 255, 255),	// 0
                 new RGBTriple(0, 255, 255),	// 1
                 new RGBTriple(255, 0, 255),	// 2
                 new RGBTriple(255, 255, 0),	// 3
                 new RGBTriple(0, 0, 255),		// 4
                 new RGBTriple(0, 255, 0),		// 5
                 new RGBTriple(255, 0, 0),		// 6
                 new RGBTriple(0,0,0)			// 7
             };
		 byt = floydSteinbergDither(img, palette);

    	 int[][] ret = new int[orig[0].length][orig[0][0].length];

		 for (int x=0;x<orig[0].length;x++)
			 for (int y=0;y<orig[0][0].length;y++) {
				ret[x][y]=(int)byt[x][y]; 
			 }
    	 
    	 return ret;
     }

 
 }
